/***************************************************************************
 *   This is a part of the AMCAX Web CAD.                                  *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/
import {
  cadAppLog,
  ConstraintType,
  CoreEngine,
  CurveStyle,
  ISketcherData,
  ParameterObjectType,
  RawMeasureResult,
  Tuple3,
} from '@amcax/base';
import { MessageTip } from '@app-base/common/utils/MessageTip';
import { ReturnDataInfo } from '@app-base/environments/nextcad/commands/CmdBase';
import {
  AnnotationCreateParams,
  AnnotationUpdateParams,
} from '@app-base/environments/nextcad/commands/sketch/dimension/types';
import { ctx2, docMgr } from '@app-cad/module';
import { Mark } from '@app-cad/types';
import { omitBy } from 'lodash';
import { Vector2tuple, Vector3, Vector3Tuple } from 'three-legacy';
import { Constants } from '../common/Constants';
import { cmdMgr } from '../manager/CmdManager';
import { getErrorMessage } from './errors';
import { AnnotationData } from '@app-base/environments/nextcad/commands/sketch/cmd-render-pick/type';

type SketchCurve =
  | 'Line'
  | 'Polygon'
  | 'Circle'
  | 'ArcOfCircle'
  | 'Ellipse'
  | 'ArcOfEllipse'
  | 'Bspline'
  | 'Point'
  | 'Rabbet'
  | 'Rect';

export const wsApi = {
  getEngine: () => {
    return ctx2.get(Constants.CORE_ENGINE) as CoreEngine;
  },

  execCmd: (params, returnFullResponse?: boolean, skipError = false) => {
    return wsApi
      .getEngine()
      .execCmd(
        omitBy(params, (v) => v == null),
        returnFullResponse,
      )
      .catch((error) => {
        if (!skipError) {
          MessageTip.error(`执行失败：${getErrorMessage(error)}`);
        }

        throw error;
      });
  },

  clearVisualData: (dxid: string) => {
    wsApi.execCmd({ c: 'ClearVisualData', o: dxid });
  },

  // start Transaction
  startTransaction: async (params?: any) => {
    return await wsApi.execCmd({ c: 'StartTransaction', ...params });
  },
  setArguments: async (params?: any) => {
    return await wsApi.execCmd({ c: 'SetArguments', ...params });
  },
  executeTransaction: async (params?: any, returnFullResponse = false) => {
    try {
      const data: any = await wsApi.execCmd(
        { c: 'ExecuteTransaction', ...params },
        returnFullResponse,
      );
      if (data) {
        // 成功的情况，返回处理后的数据
        return data;
      } else {
        // 错误或异常情况，抛出错误
        MessageTip.error(`Transaction failed with nio data`);
        throw new Error(`Transaction failed with no data`);
      }
    } catch (error) {
      console.error('Error in executeTransaction:', error);
      throw error; // 将错误向上抛出
    }
  },
  endTransaction: async (params?: any) => {
    const res = await wsApi.execCmd({ c: 'EndTransaction', ...params });
    cmdMgr.increaseUndo();
    return res;
  },
  abortTransaction: async (params?: any) => {
    return await wsApi.execCmd({ c: 'AbortTransaction', ...params });
  },
  // end Transaction

  getObjects: async (dxids?: string[]): Promise<any> => {
    const cmd: {
      c: string;
      o: string[] | undefined;
    } = { c: 'GetObjects', o: undefined };
    if (dxids) {
      cmd.o = dxids;
    }
    return wsApi.execCmd(cmd);
  },
  openNextModel: async (path: string) => {
    return await wsApi.execCmd({ c: 'OpenNextModel', t: path });
  },
  openDocument: async (version: string | number, readonly: boolean) => {
    return await wsApi.execCmd({ c: 'OpenDocument', readonly, version });
  },
  getDocumentProperties: async () => {
    const cmd = {
      c: 'GetObjectProperty',
    };
    const res = await wsApi.execCmd(cmd);
    return res.Document;
  },
  getDocumentMaterials: async (): Promise<any[]> => {
    const cmd = {
      c: 'GetMaterials',
    };
    const res = await wsApi.execCmd(cmd);
    return res.Materials ? res.Materials : [];
  },
  undo: async (e?: string) => {
    return wsApi.execCmd({ c: 'Undo', e });
  },
  redo: async (e?: string) => {
    return wsApi.execCmd({ c: 'Redo', e });
  },

  // ======= 装配 ==========
  // ====== 设置颜色或半透明 ======
  setColorAndOpacity: (
    asmDxids: string[],
    options: { color?: string; opacity?: number }[], // 改为数组
  ) => {
    if (asmDxids.length !== options.length) {
      throw new Error('The length of asmDxids and options must match.');
    }

    return wsApi.execCmd({
      c: 'EditColor',
      a: asmDxids.reduce(
        (acc, dxid, index) => {
          const key = dxid.includes(':') ? dxid : `${dxid}:all`;
          const option = options[index];
          acc[key] = {
            ...(option?.color ? { c: option?.color } : {}),
            ...(option?.opacity !== undefined ? { a: option?.opacity } : {}),
          };
          return acc;
        },
        {} as Record<string, { c?: string; a?: number }>,
      ),
    });
  },

  // 替换产品/零件
  assembleExchangeProduct: async (params: {
    o: string;
    docid: string;
    docver: string;
  }) => {
    return wsApi.execCmd({ c: 'ReplaceSubDoc', e: 'ASSEMBLY', ...params });
  },
  // 干涉检查
  interferenceCheck: ({
    objects,
    exclude,
    includeCoincide,
    calEntityForPart,
  }: {
    objects: string[];
    exclude: string[];
    includeCoincide: boolean;
    calEntityForPart: boolean;
  }) =>
    wsApi.execCmd({
      c: 'InterferenceCheck',
      a: {
        objects,
        exclude: exclude?.length > 0 ? exclude : null,
        includeCoincide,
        calEntityForPart,
      },
      e: 'ASSEMBLY',
    }),
  // 间隙检查
  intervalCheck: ({
    objects,
    minInterval,
    checkRange,
    ignoreHidden = true,
    ignoreEqualInterval = false,
    treatAssemblyAsOneObject = false,
  }: {
    objects: string[];
    minInterval: number;
    checkRange: 'checkSelectedItems' | 'checkSelectedItemWithOthers';
    ignoreHidden: boolean;
    ignoreEqualInterval: boolean;
    treatAssemblyAsOneObject: boolean;
  }) =>
    wsApi.execCmd({
      c: 'IntervalCheck',
      a: {
        objects,
        minInterval,
        checkRange,
        ignoreHidden,
        ignoreEqualInterval,
        treatAssemblyAsOneObject,
      },
      e: 'ASSEMBLY',
    }),
  // 孔对齐检查
  holeAlignCheck: ({
    objects,
    deviation,
    ignoreHidden = true,
    ignoreEqualInterval = false,
    treatAssemblyAsOneObject = false,
  }: {
    objects: string[];
    deviation: [number, number];
    ignoreHidden: boolean;
    ignoreEqualInterval: boolean;
    treatAssemblyAsOneObject: boolean;
  }) =>
    wsApi.execCmd({
      c: 'HoleAlignCheck',
      a: {
        objects,
        deviation,
        ignoreHidden,
        ignoreEqualInterval,
        treatAssemblyAsOneObject,
      },
      e: 'ASSEMBLY',
    }),
  /***
   * 得到面的信息
   *   Undefined
   *   Plane
   *   Cylinder
   *   Cone
   *   Sphere
   *   Torus
   *   SurfaceOfExtrusion
   *   SurfaceOfRevolution
   *   BezierSurface
   *   BSplineSurface
   *   TrimmedSurface
   *   OffsetSurface
   *   OtherSurface
   ***/
  getSurfaceType: async (id: string) => {
    const cmd = {
      c: 'GetSurfaceType',
      a: {
        surface: id,
      },
    };
    const res = await wsApi.execCmd(cmd);
    return res;
  },
  //
  delete(dxid: string | string[]) {
    const result = wsApi.execCmd({ c: 'Delete', o: dxid });
    // cmdMgr.increaseUndo()
    cmdMgr.increaseUndo();
    return result;
  },
  copy: async (params?: any) => {
    const result = await wsApi.execCmd({ c: 'Copy', ...params });
    cmdMgr.increaseUndo();
    return result;
  },
  makeEuclid: async (params?: any) => {
    const result = await wsApi.execCmd({ c: 'MakeEuclidV1', ...params });
    cmdMgr.increaseUndo();
    return result;
  },
  makeEuclidV2: async (params?: any) => {
    const result = await wsApi.execCmd({ c: 'MakeEuclidV2', ...params });
    cmdMgr.increaseUndo();
    return result;
  },
  makeArray: async (
    dxid: string,
    count: number,
    direction: string,
    distance: number,
  ) => {
    const result = await wsApi.execCmd({
      c: 'CreateArray',
      o: dxid,
      count,
      direction,
      distance,
    });
    cmdMgr.increaseUndo();
    return result;
  },
  importDocument: ({
    documentId,
    version,
  }: {
    documentId: string;
    version: string;
  }) => {
    return wsApi.execCmd({
      c: 'ImportFromOtherDoc',
      doc: documentId,
      ver: version,
    });
  },
  importModel: async (params?: any) => {
    return await wsApi.execCmd({ c: 'ImportModel', ...params });
  },
  import2DPoints: async (params?: any) => {
    return await wsApi.execCmd({ c: 'import2DPoints', ...params });
  },
  exportModel: async (params?: any) => {
    return await wsApi.execCmd({ c: 'ExportModel', ...params });
  },
  setTransform: async (params?: any) => {
    const result = await wsApi.execCmd({ c: 'SetTransform', ...params });
    cmdMgr.increaseUndo();
    return result;
  },

  getParentId: () => {
    const parentId = docMgr.workingObjectDxid;
    return (
      parentId ??
      docMgr.documentObjects.findLast((item) => item.type === 'GeomBox')?.dxid
    );
  },

  create: async (
    params: any,
    preview = false,
    returnFullResponse = false,
    needIncreaseUndo = true,
  ) => {
    const result = await wsApi.execCmd(
      {
        p: preview,
        parent: wsApi.getParentId(),
        ...params,
      },
      returnFullResponse,
    );

    if (needIncreaseUndo && !preview) {
      cmdMgr.increaseUndo();
    }

    return result;
  },

  createGeomBox: (name?: string) => wsApi.execCmd({ c: 'CreateGeomBox', name }),
  createParameterSet: (parent?: string) =>
    wsApi.execCmd({ c: 'CreateParameterSet', parent }),

  createParameterObject: (
    params: {
      type: ParameterObjectType;
      expr: string | number;
      unit?: string;
    },
    parent?: string,
  ) => wsApi.execCmd({ c: 'CreateParameterObj', parent, a: params }),

  editParameterObject: (
    editTarget: string,
    params: { expr: string | number; unit?: string },
  ) => wsApi.execCmd({ c: 'EditParameterObj', o: editTarget, a: params }),

  // ====== 3D生成点命令 ======
  createPoint: async (params: any, preview = false) => {
    return wsApi.create(
      {
        c: 'CreateVertex',
        a: {
          mode: 'coordinate',
          point: params,
        },
      },
      preview,
    );
  },

  createPointByPoint: async (params: any, preview = false) => {
    return wsApi.create(
      {
        c: 'CreateVertex',
        a: {
          mode: '2point',
          ...params,
        },
      },
      preview,
    );
  },

  // ====== 3D曲线命令 ======
  createCurve: async (type: string, params: any, preview = false) => {
    return wsApi.create(
      {
        c: 'CreateCurve',
        type,
        a: params,
      },
      preview,
    );
  },

  createLine: async ({
    point1,
    point2,
  }: {
    point1: Vector3 | string;
    point2: Vector3 | string;
  }) => {
    return await wsApi.createCurve('Line', {
      mode: '2point',
      point1:
        typeof point1 === 'string' ? point1 : [point1.x, point1.y, point1.z],
      point2:
        typeof point2 === 'string' ? point2 : [point2.x, point2.y, point2.z],
    });
  },
  //折线
  createPolyline: async (points, preview = false) => {
    return await wsApi.createCurve(
      'Polygon',
      {
        points,
      },
      preview,
    );
  },

  createLineByDotVector: async (
    params: {
      origin: string;
      vector: string;
      forward: number;
      back: number;
    },
    preview = false,
  ) => {
    return await wsApi.createCurve(
      'Line',
      {
        mode: 'vector',
        ...params,
      },
      preview,
    );
  },

  createLineByCurveAngle: async (
    params: {
      point: string;
      curve: string;
      forward: number;
      back: number;
      angle: number;
    },
    preview = false,
  ) => {
    return await wsApi.createCurve(
      'Line',
      {
        mode: 'tangent',
        ...params,
      },
      preview,
    );
  },
  createPolygon: async (points: Vector3[]) => {
    const _points = points.map((point: Vector3) => {
      return [point.x, point.y, point.z];
    });
    return await wsApi.createCurve('Polygon', {
      points: _points,
    });
  },
  createRectangle: async (points: Vector3[]) => {
    const _points = points.map((point: Vector3) => {
      return [point.x, point.y, point.z];
    });
    return await wsApi.createCurve('Polygon', {
      points: _points,
    });
  },
  createBspline: async (points: Vector3[]) => {
    const _points = points.map((point: Vector3) => {
      return [point.x, point.y, point.z];
    });
    return await wsApi.createCurve('Bspline', {
      points: _points,
    });
  },
  createCircle: async (center: Vector3, radius: number, normal: number[]) => {
    const result = await wsApi.createCurve('Circle', {
      mode: 'center-radius',
      center: [center.x, center.y, center.z],
      radius: radius,
      normal,
    });
    return result;
  },

  joinCurve: (curves: string[]) => {
    return wsApi.createCurve('Join', { curves });
  },

  breakCurve: (curve: string, cutter: string[]) => {
    return wsApi.createCurve('Break', { curve, cutter });
  },

  createSurface: async (type: string, params: any, preview = false) => {
    return wsApi.create(
      {
        c: 'CreateSurface',
        type,
        a: params,
      },
      preview,
    );
  },

  sewSurface: (surfaces: string[], tol: number) => {
    return wsApi.createSurface('Sew', { surfaces, tol });
  },

  createEllipse: async (
    center: Vector3,
    major: number,
    minor: number,
    majorDir: number[],
    normal: number[],
  ) => {
    return await wsApi.createCurve('Ellipse', {
      center: [center.x, center.y, center.z],
      major: major,
      minor: minor,
      majorDir: majorDir,
      normal: normal,
    });
  },
  createArc: async (
    center: Vector3,
    point1: Vector3,
    point2: Vector3,
    normal: number[],
  ) => {
    const result = await wsApi.createCurve('ArcOfCircle', {
      center: [center.x, center.y, center.z],
      point1: [point1.x, point1.y, point1.z],
      point2: [point2.x, point2.y, point2.z],
      normal,
    });
    return result;
  },
  createHelix: async (
    pitch: number,
    height: number,
    radius: number,
    angle: number,
    leftup: boolean,
  ) => {
    return await wsApi.createCurve('Helix', {
      pitch: pitch,
      height: height,
      radius: radius,
      angle: angle,
      leftup: leftup,
    });
  },
  // ====== 3D曲线命令 ======
  createScale: (
    dxid: string,
    params: { point: string; scale: number },
    preview = false,
  ) => {
    return wsApi.create(
      {
        c: 'Scale',
        o: dxid,
        a: params,
      },
      preview,
    );
  },

  createExtrude: async (
    dxids: string[],
    height: number,
    solid: boolean = true,
  ) => {
    const documents = docMgr.flatDocumentObjects;
    dxids.forEach(async (dxid) => {
      const document = documents.filter(
        (document) => document.dxid === dxid,
      )[0];
      const vector = new Vector3(
        document.placement[1][0],
        document.placement[1][1],
        document.placement[1][2],
      ).multiplyScalar(height);
      await wsApi.execCmd({
        c: 'CreateExtrude',
        a: {
          profile: dxids,
          vector: [vector.x, vector.y, vector.z],
          solid: solid,
        },
      });
      cmdMgr.increaseUndo();
    });
  },

  // ====== 坐标系 ======
  createFrame: async (
    origin: string | [number, number, number],
    zdir: [number, number, number] = [0, 0, 1],
    xdir: [number, number, number] = [1, 0, 0],
  ) => {
    return await wsApi.create({
      c: 'CreateFrame',
      a: {
        origin,
        zdir,
        xdir,
      },
    });
  },

  // 规则体
  async createPrimitiveNew(type: string, params: any, preview = false) {
    return await wsApi.create({
      c: 'CreatePrimitive',
      p: preview,
      type: type,
      a: params,
    });
  },

  // ====== 基本图形命令 ======
  createPrimitive: async (
    type: string,
    params: any,
    placement?: any,
    preview = false,
  ) =>
    wsApi.create(
      {
        c: 'CreatePrimitive',
        type,
        a: params,
        placement,
      },
      preview,
    ),

  createSphere: async (center: Vector3, radius: number) => {
    const result = await wsApi.createPrimitive(
      'Sphere',
      {
        radius: radius,
      },
      [
        [center.x, center.y, 0],
        [0, 0, 1],
        [1, 0, 0],
      ],
    );
    return result;
  },
  createTube: async (
    radius1: number,
    radius2: number,
    height: number,
    angle: number,
  ) => {
    const result = await wsApi.createPrimitive('Tube', {
      radius1: radius1,
      radius2: radius2,
      height: height,
      angle: angle,
    });
    return result;
  },
  createCone: async (
    radius1: number,
    radius2: number,
    height: number,
    angle: number,
  ) => {
    const result = await wsApi.createPrimitive('Cone', {
      radius1: radius1,
      radius2: radius2,
      height: height,
      angle: angle,
    });
    return result;
  },
  createWedge: async (
    xmin: number,
    xmax: number,
    ymin: number,
    ymax: number,
    zmin: number,
    zmax: number,
    x2min: number,
    x2max: number,
    z2min: number,
    z2max: number,
  ) => {
    return await wsApi.createPrimitive('Wedge', {
      xmin: xmin,
      xmax: xmax,
      ymin: ymin,
      ymax: ymax,
      zmin: zmin,
      zmax: zmax,
      x2min: x2min,
      x2max: x2max,
      z2min: z2min,
      z2max: z2max,
    });
  },
  createPyramid: async (
    polygon: number,
    circumradius: number,
    height: number,
  ) => {
    return await wsApi.createPrimitive('Pyramid', {
      polygon: polygon,
      circumradius: circumradius,
      height: height,
    });
  },
  // ====== 基本图形命令 ======

  createCompound: async (dxids: string[]) => {
    return wsApi.execCmd({
      c: 'CreateCompound',
      o: dxids,
    });
  },
  createSplit: async (dxid: string) => {
    return wsApi.execCmd({
      c: 'CreateSplit',
      a: {
        base: dxid,
        tool: dxid,
      },
    });
  },
  // 实体混合
  createEntityMix: async (params: any, isPreview: boolean = false) => {
    return wsApi.execCmd({
      c: 'CreateEntityMix',
      p: isPreview,
      a: {
        ...params,
      },
    });
  },
  createSweep: async (p_dxids: string[], s_dxids: string[]) => {
    return wsApi.execCmd({
      c: 'CreateSweep',
      a: {
        profile: p_dxids,
        spine: s_dxids,
      },
    });
  },
  // 拉伸凸台
  createStretch: async (params: any, preview = false) => {
    return wsApi.create(
      {
        c: 'CreateExtrude',
        a: params,
      },
      preview,
    );
  },
  // 圆角
  createFillet: async (params: any, preview = false) => {
    return wsApi.create(
      {
        c: 'CreateFillet',
        a: params,
      },
      preview,
    );
  },
  // 倒角
  createChamfer: async (params: any, preview = false) => {
    return wsApi.create(
      {
        c: 'CreateChamfer',
        a: params,
      },
      preview,
    );
  },
  // 放样
  createLoft(profile, preview) {
    return wsApi.execCmd({
      c: 'CreateSweep',
      p: preview,
      a: {
        profile,
      },
    });
  },
  // 抽壳
  createShell(params, preview = false) {
    return wsApi.execCmd({
      c: 'CreateThickShell',
      p: preview,
      a: params,
    });
  },
  // 切除
  createCutter(params, preview = false) {
    return wsApi.execCmd({
      c: 'CreateCutter',
      p: preview,
      a: params,
    });
  },
  // 拔模
  createDraft(params, preview = false) {
    return wsApi.execCmd({
      c: 'CreateDraft',
      p: preview,
      a: params,
    });
  },
  createRevolve: async (p_dxids: string[], point: Vector3, normal: Vector3) => {
    return wsApi.execCmd({
      c: 'CreateRevol',
      a: {
        profile: p_dxids,
        axis: [
          [point.x, point.y, point.z],
          [normal.x, normal.y, normal.z],
        ],
      },
    });
  },
  async setLabel(dxid: string, label: string) {
    return await wsApi.execCmd({ c: 'SetLabel', o: dxid, l: label });
  },
  async setParams(
    dxid: string,
    params?: any,
    preview = false,
    returnFullResponse = false,
  ) {
    return await wsApi.execCmd(
      { c: 'SetParams', o: dxid, a: params || {}, p: preview },
      returnFullResponse,
    );
  },
  async setPlacement(
    dxid: string,
    pos: number[],
    norm: number[],
    xdir: number[],
  ) {
    return await wsApi.execCmd({
      c: 'SetPlacement',
      o: dxid,
      placement: [pos, norm, xdir],
    });
  },

  // 设置颜色
  /**
   * @param dxid 要设置颜色的对象
   * @param color 颜色
   * @param faceIndex 面索引，-1表示所有面
   */
  async setColor(dxid: string, color: string, faceIndex: number = -1) {
    return await wsApi.execCmd({
      c: 'SetColor',
      o: dxid,
      a: {
        face: faceIndex,
        color: color,
      },
    });
  },

  // 设置是否可视
  async setVisible(dxid: string, visible: boolean) {
    return await wsApi.execCmd({
      c: 'SetVisibility',
      o: dxid,
      visible: visible,
      recursive: false,
    });
  },

  // 属性 Properly
  getProperty: async () => {
    return await wsApi.execCmd({ c: 'GetProperty' });
  },

  // 材质
  // 添加一种材质
  async addMaterial(material: any) {
    return await wsApi.execCmd({
      c: 'AddMaterial',
      a: material,
    });
  },

  // undo redo
  async getUndoSize() {
    return await wsApi.execCmd({ c: 'GetUndoSize' });
  },
  // async updateDocumentAndreadVisualData(data: any) {
  //   const { objects } = await wsApi.getObjects()
  //   // ctx2.setDocumentObjects(objects)
  //   docMgr.documentObjects = objects
  //   return ctx2.modelRender.readVisualData(data)
  // },

  // ====== 草图接口 ======
  // 获取面的frame
  async getFaceFrame(dxid: string) {
    return await wsApi.execCmd({
      c: 'GetFaceFrame',
      o: dxid,
    });
  },
  // 创建草图
  async createSketcher(frame: Vector3Tuple[] | string) {
    const params = {
      parent: wsApi.getParentId(),
      e: 'SKETCHER',
      c: 'CreateSketcher',
      a: { frame },
    };
    cadAppLog('CreateSketcher:', params);
    return await wsApi.execCmd(params);
  },
  // 获取草图数据
  async getSketchCurves(sketchId: string, skipError = false) {
    const res = await wsApi.execCmd(
      {
        e: 'SKETCHER',
        c: 'GetCurves',
        o: sketchId,
      },
      false,
      skipError,
    );

    return res as ISketcherData;
  },
  // 获取草图数据
  async getSketchCurve(skid: string, curves: string[]) {
    return (await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'GetCurve',
      o: skid,
      a: {
        curves,
      },
    })) as ISketcherData;
  },
  // 获取直线相交点
  async getSketchLineInterSect(
    skid: string,
    curve1: string,
    curve2: string,
    isPreview: boolean = true,
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Intersect',
      o: skid,
      p: isPreview,
      a: {
        curve1,
        curve2,
      },
    });
  },
  // 拖动草图
  async moveSketcher(
    skid: string,
    curve: string,
    end: Vector2tuple,
    start: Vector2tuple,
    isPreview?: boolean,
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Drag',
      o: skid,
      p: isPreview,
      a: {
        curve,
        end,
        start,
      },
    });
  },
  // 剪切
  async trimSketcherCurve(
    skid: string,
    curve: string,
    point: string | Vector2tuple,
    isPreview?: boolean,
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Trim',
      o: skid,
      p: isPreview,
      a: {
        curve,
        point,
      },
    });
  },
  // 草图分割
  async divideSketchCurve(
    skid: string,
    curveId: string,
    point: Vector2tuple[],
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Break',
      o: skid,
      p: false,
      a: {
        curve: curveId,
        point,
      },
    });
  },

  // 退出草图(退出草图，将会更新对应的所有特征)
  async exitSketcher(skid: string) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'ExitSketcher',
      o: skid,
    });
  },
  // 创建图形
  async createSketchCurve(
    skid: string,
    type: SketchCurve,
    params?: any,
    isPreview?: boolean,
  ) {
    cmdMgr.increaseUndo();
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'CreateCurve',
      o: skid,
      type,
      a: params,
      p: isPreview,
    });
  },
  // 修改线段
  async editSketchCurve(
    skid: string,
    type: SketchCurve,
    params,
    isPreview?: boolean,
  ) {
    cmdMgr.increaseUndo();
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'EditCurve',
      o: skid,
      a: params,
      p: isPreview,
    });
  },
  async createSketchRect(skid: string, params?: any) {
    return wsApi.createSketchCurve(skid, 'Rect', params);
  },
  // 删除图形
  async deleteSketchCurve(skid: string, curveIds: string[]) {
    cmdMgr.increaseUndo();
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'DeleteCurve',
      o: skid,
      a: {
        curves: curveIds,
      },
    });
  },
  // 线段
  async createSketchLine(skid: string, params?: any) {
    return wsApi.createSketchCurve(skid, 'Line', params);
  },
  // 修改线条
  async editSketchLine(skid: string, params?: any) {
    return wsApi.editSketchCurve(skid, 'Line', params);
  },
  // 多边形
  async createSketchPolygon(skid: string, params?: any) {
    return wsApi.createSketchCurve(skid, 'Polygon', params);
  },
  // 圆
  async createSketchCircle(
    skid: string,
    params?: {
      center: Vector2tuple | string;
      radius: number;
      curveStyle?: CurveStyle;
      constraints?;
      annotations?;
    },
  ) {
    return wsApi.createSketchCurve(skid, 'Circle', params);
  },
  // 三点圆
  async createSketchCircle3P(skid: string, params?: any) {
    return wsApi.createSketchCurve(skid, 'Circle', params);
  },
  // 三线切圆
  async createSketchCircle3Curves(sketchId: string, curveIds: string[]) {
    return wsApi.createSketchCurve(sketchId, 'Circle', {
      mode: 'three-curve',
      curves: curveIds,
    });
  },
  // 圆弧
  async createSketchArcOfCircle(skid: string, params?: any) {
    return wsApi.createSketchCurve(skid, 'ArcOfCircle', params);
  },
  // 椭圆
  async createSketchEllipse(skid: string, params?: any) {
    return wsApi.createSketchCurve(skid, 'Ellipse', params);
  },
  // 椭圆弧
  async createSketchEllipseArc(skid: string, params?: any) {
    return wsApi.createSketchCurve(skid, 'ArcOfEllipse', params);
  },
  async createRabbet(skid: string, params?: any) {
    return wsApi.createSketchCurve(skid, 'Rabbet', params);
  },
  // 曲线
  async createSketchBSpline(skid: string, params?: any, isPreview?: boolean) {
    return wsApi.createSketchCurve(skid, 'Bspline', params, isPreview);
  },
  //点
  async createSketchPoint(skid: string, params?: any) {
    return wsApi.createSketchCurve(skid, 'Point', params);
  },
  // 获取标注
  async getSketchAnnotations(skid: string) {
    return (await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'GetAnnotations',
      o: skid,
      a: {},
    })) as { annotations: AnnotationData[] };
  },
  // 标注
  async addDimension(skid: string, params: AnnotationCreateParams) {
    return (await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'CreateAnnotation',
      o: skid,
      a: {
        curve: params.curve[0], //标注起始线条ID
        target: params.curve[1] || params.curve[0], // 标注结束线条ID； 对于只有一个对象的，与curve相同
        type: params.type,
        value: params.value,
        points: params.points,
      },
    })) as ReturnDataInfo;
  },
  async deleteDimension(skid: string, params: any) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'DeleteAnnotation',
      o: skid,
      a: params,
    });
  },
  async updateDimension(skid: string, params: AnnotationUpdateParams) {
    return (await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'ModifyAnnotation',
      o: skid,
      a: params,
    })) as ReturnDataInfo;
  },
  // 添加约束
  async createSketchConstraint(
    skid: string,
    srcCurveId: string,
    targetCurveId: string,
    type: ConstraintType,
    val: number,
    axis?: string,
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'AddConstraint',
      o: skid,
      a: {
        curve: srcCurveId,
        target: targetCurveId,
        type,
        val,
        axis,
      },
    });
  },
  // 批量添加约束
  async createBatchSketchConstraint(
    sketchId: string,
    curves: string[],
    type: ConstraintType,
    val = 0,
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'AddBatchConstraint',
      o: sketchId,
      a: {
        curves,
        type,
        val,
      },
    });
  },
  // 删除约束
  async deleteSketchConstraint(
    skid: string,
    srcCurveId: string,
    targetCurveId: string,
    type: ConstraintType,
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'DeleteConstraint',
      o: skid,
      a: {
        curve: srcCurveId,
        target: targetCurveId,
        type,
      },
    });
  },
  // 移动
  async moveSketchCurve(
    skid: string,
    curveIds: string[],
    vector: THREE.Vector2,
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Move',
      o: skid,
      a: {
        curves: curveIds,
        vector: [vector.x, vector.y],
      },
    });
  },
  // 旋转
  async rotateSketchCurve(
    skid: string,
    curveIds: string[],
    center: THREE.Vector2,
    angle: number,
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Rotate',
      o: skid,
      a: {
        curves: curveIds,
        center: [center.x, center.y],
        angle,
      },
    });
  },
  // 缩放
  async scaleSketchCurve(
    skid: string,
    curveIds: string[],
    center: THREE.Vector2,
    factor: number,
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Scale',
      o: skid,
      a: {
        curves: curveIds,
        center: [center.x, center.y],
        factor,
      },
    });
  },
  // 镜像
  async mirrorSketchCurve(
    skid: string,
    curveIds: string[],
    point: THREE.Vector2,
    axis_point?: THREE.Vector2,
    axis_direction?: THREE.Vector2,
  ) {
    const params = {
      e: 'SKETCHER',
      c: 'Mirror',
      o: skid,
      a: {
        curves: curveIds,
        point: [point.x, point.y],
      },
    };
    if (axis_point) {
      params.a['axis'] = [axis_point.x, axis_point.y];
    }
    if (axis_direction) {
      params.a['axis'] = [axis_direction.x, axis_direction.y];
    }
    return await wsApi.execCmd(params);
  },
  // 草图偏移
  async offsetSketchCurve(
    skid: string,
    curve: string,
    length: number,
    isPreview: boolean,
    selectChain: boolean = true,
    baseConstruct: boolean = false,
    doubleDirect: boolean = false,
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Offset',
      o: skid,
      p: isPreview,
      a: { curve, length, selectChain, baseConstruct, doubleDirect },
    });
  },

  // 阵列
  async arraySketchCurve(
    skid: string,
    curveIds: string[],
    count: number,
    direction?: THREE.Vector2,
    distance?: number,
    center?: THREE.Vector2,
    angle?: number | string,
    isPreview?: boolean,
    reverse?: boolean,
  ) {
    const params = {
      e: 'SKETCHER',
      c: 'Array',
      o: skid,
      p: isPreview,
      a: {
        curves: curveIds,
        count,
        reverse,
      },
    };
    if (direction) {
      params.a['direction'] = [direction.x, direction.y];
      params.a['distance'] = distance;
    } else if (center) {
      params.a['center'] = [center.x, center.y];
      params.a['angle'] = angle;
    }

    return await wsApi.execCmd(params);
  },
  // 断开
  async breakSketchCurve(skid: string, curveId: string) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Break',
      o: skid,
      a: {
        curve: curveId,
      },
    });
  },
  // 修剪
  async trimSketchCurve(skid: string, curveId: string, point: THREE.Vector2) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Trim',
      o: skid,
      a: {
        curve: curveId,
        point: [point.x, point.y],
      },
    });
  },
  // 草图镜像
  async mirrorSketchCurves(skid: string, params, isPreview?: boolean) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Mirror',
      o: skid,
      p: isPreview,
      a: params,
    });
  },
  // 圆角
  async filletSketchCurve(
    skid: string,
    curveIds: string[],
    cut: number,
    radius: number | string,
    isPreview?: boolean,
    clickcrv1?: number[],
    clickcrv2?: number[],
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Fillet',
      o: skid,
      p: isPreview,
      a: {
        curves: curveIds,
        radius,
        cut,
        clickcrv1,
        clickcrv2,
      },
    });
  },
  // 草图倒角
  async chamferSketcherCurve(
    skid: string,
    curveIds: string[],
    isPreview: boolean,
    clickcrv1: number[],
    clickcrv2: number[],
    length1: number,
    length2: number,
    cut: number = 2,
  ) {
    return await wsApi.execCmd({
      e: 'SKETCHER',
      c: 'Chamfer',
      o: skid,
      p: isPreview,
      a: {
        curves: curveIds,
        cut,
        clickcrv1,
        clickcrv2,
        length1,
        length2,
      },
    });
  },
  // 倒角
  async chamferSketchCurve(
    skid: string,
    curveIds: string[],
    cut: number,
    length1?: number,
    length2?: number,
    hypotenuse?: number,
    angle?: number,
  ) {
    const params = {
      e: 'SKETCHER',
      c: 'Chamfer',
      o: skid,
      a: {
        curves: curveIds,
        cut,
      },
    };
    if (cut === 0) {
      if (length1) {
        params.a['length1'] = length1;
      }
      if (length2) {
        params.a['length2'] = length2;
      }
    } else if (cut === 1) {
      if (hypotenuse) {
        params.a['hypotenuse'] = hypotenuse;
      }
      if (angle) {
        params.a['angle'] = angle;
      }
    } else if (cut === 2) {
      if (length1) {
        params.a['length1'] = length1;
      }
      if (angle) {
        params.a['angle'] = angle;
      }
    }
    return await wsApi.execCmd(params);
  },
  // 拉伸切除
  async extrudeCut(params, preview: boolean = false) {
    const result = await wsApi.execCmd({
      c: 'CreateHoleCutter',
      type: 'HoleE',
      a: params,
      p: preview,
    });
    if (!preview) {
      cmdMgr.increaseUndo();
    }
    return result;
  },

  // 旋转凸台
  async createRevol(params, preview: boolean = false) {
    const result = await wsApi.execCmd({
      c: 'CreateRevol',
      a: params,
      p: preview,
    });
    if (!preview) {
      cmdMgr.increaseUndo();
    }
    return result;
  },

  // 旋转切除
  async createRecolCut(params, preview: boolean = false) {
    const result = await wsApi.execCmd({
      c: 'CreateHoleCutter',
      type: 'HoleR',
      a: params,
      p: preview,
    });
    if (!preview) {
      cmdMgr.increaseUndo();
    }
    return result;
  },

  // 线性阵列/圆周阵列
  async createArray(dxid: string, params, preview: boolean = false) {
    const result = await wsApi.execCmd({
      c: 'CreateArray',
      p: preview,
      o: dxid,
      a: params,
    });
    if (!preview) {
      cmdMgr.increaseUndo();
    }
    return result;
  },
  // 装配 线性阵列/圆周阵列
  async createProductArray(dxid: string, params, preview: boolean = false) {
    const result = await wsApi.execCmd({
      c: 'Array',
      p: preview,
      o: dxid,
      a: params,
      e: 'ASSEMBLY',
    });
    if (!preview) {
      cmdMgr.increaseUndo();
    }
    return result;
  },

  // 特征镜像
  async createMirror(
    dxids: string[] | string,
    params,
    preview: boolean = false,
  ) {
    const result = await wsApi.execCmd({
      c: 'Mirror',
      e: 'ASSEMBLY',
      p: preview,
      o: dxids,
      a: params,
    });
    if (!preview) {
      cmdMgr.increaseUndo();
    }
    return result;
  },
  // 加厚
  async createThickness(params, preview: boolean = false) {
    return await wsApi.create({
      c: 'CreateThickness',
      p: preview,
      a: params,
    });
  },

  // 扫掠
  async createSweepFeature(params, preview: boolean = false) {
    return await wsApi.create({
      c: 'CreateSweep',
      p: preview,
      a: params,
    });
  },

  // 旋转扫掠
  async createRevolveSweep(params, preview: boolean = false) {
    return await wsApi.create({
      c: 'CreateSurface',
      type: 'RotationSweep',
      p: preview,
      a: params,
    });
  },

  // 放样
  async createLoftFeature(params, preview: boolean = false) {
    return await wsApi.create({
      c: 'CreateLoft',
      p: preview,
      a: params,
    });
  },

  // 曲面炸开
  async explodeSurface(params, preview: boolean = false) {
    return await wsApi.create({
      c: 'CreateSurface',
      type: 'Explode',
      p: preview,
      a: params,
    });
  },

  async chamferSketchCurve0(
    skid: string,
    curveIds: string[],
    length1: number,
    length2: number,
  ) {
    return wsApi.chamferSketchCurve(skid, curveIds, 0, length1, length2);
  },
  async chamferSketchCurve1(
    skid: string,
    curveIds: string[],
    hypotenuse: number,
    angle: number,
  ) {
    return wsApi.chamferSketchCurve(skid, curveIds, 1, hypotenuse, angle);
  },
  async chamferSketchCurve2(
    skid: string,
    curveIds: string[],
    length1: number,
    angle: number,
  ) {
    return wsApi.chamferSketchCurve(skid, curveIds, 2, length1, angle);
  },

  // 修改草图支持面
  async editSketchPlane(
    sketchId: string,
    frame: Tuple3<Vector3Tuple> | string,
  ) {
    return wsApi.execCmd({
      e: 'SKETCHER',
      c: 'EditSketcher',
      o: sketchId,
      a: {
        frame,
      },
    });
  },

  // ====== 草图接口 ======

  // ====== 材质接口 ======
  async addMaterials() {
    const params = {
      color: '', // 可以没有
      texture: '', // 可以为空或没有
      ambient: '', // 可以没有
      diffuse: '', // 可以没有
      emissive: '', // 可以没有
      specular: '', // 可以没有
      shininess: 0.2, // double, 可以没有
      transparency: 0.0, // double, 可以没有
    };
    return await wsApi.execCmd({ c: 'AddMaterial', a: params });
  },
  async editMaterials(material: any) {
    const params = Object.assign({}, material);
    if (params.dxid) {
      delete params.dxid;
    }
    if (params.faceIndex) {
      delete params.faceIndex;
    }
    return await wsApi.execCmd({ c: 'EditMaterial', a: params });
  },
  async deleteMaterials(id: number) {
    return await wsApi.execCmd({ c: 'DeleteMaterial', id });
  },
  /**
   * 给模型设置材质
   * face = -1 表示设置整体的材质 ; 从 0 开始
   * matId = -1 表示清除对应的材质
   */
  async setMaterials(dxid: string, faceIndex: number, materialId: number) {
    return await wsApi.execCmd({
      c: 'SetMaterial',
      o: dxid,
      a: { face: faceIndex, matId: materialId },
    });
  },
  // ====== 材质接口 ======

  // ====== 电力行业命令 ======
  createPrimitiveELE: async (type: string, params: any) => {
    return await wsApi.execCmd({ c: 'CreatePrimitiveELE', type, a: params });
  },
  //绝缘子
  createInsulator: async (params: any) => {
    return wsApi.createPrimitiveELE('Insulator', params);
  },
  // 电杆横架
  createEleShelf: async (params: any) => {
    return wsApi.createPrimitiveELE('EleShelf', params);
  },
  // 直角板
  createAngleBoard: async (params: any) => {
    return wsApi.createPrimitiveELE('AngleBoard', params);
  },
  // 固定铁环
  createFixedHoop: async (params: any) => {
    return wsApi.createPrimitiveELE('FixedHoop', params);
  },
  //围栏
  createFence: async (params: any) => {
    return wsApi.createPrimitiveELE('Fence', params);
  },
  // 环网柜
  createRingCabinet: async (params: any) => {
    return wsApi.createPrimitiveELE('RingCabinet', params);
  },
  // 线缆
  createCable: async (spine: string, radius: number) => {
    return wsApi.createPrimitiveELE('Cable', { spine, radius });
  },
  // ====== 电力行业命令 ======

  // ====== BIM命令 ======
  createPrimitiveBIM: async (type: string, params: any) => {
    return await wsApi.execCmd({ c: 'CreatePrimitiveBIM', type, a: params });
  },
  createStep: async (params: any) => {
    // 总宽，总高，总长，阶数 , 默认值：300， 300， 360， 6
    // 每个台阶的高 = height / steps
    // 每个台阶的宽 = length / steps
    return wsApi.createPrimitiveBIM('SideStep', params);
  },
  createStair: async (params: any) => {
    return await wsApi.execCmd({
      c: 'CreatePrimitiveBIM',
      type: 'Stairs',
      a: params,
      // startup: 左上，还是右上，值： left, right
      // 默认值： 250, 300, 10, left
    });
  },
  // createPrimitiveBIM: async (type: string, params: any, placement?: any) => {
  //   let cmd = { c: 'CreatePrimitiveBIM', type, a: params, placement: undefined }
  //   if (placement) cmd.placement = placement
  //   const result = wsApi.execCmd(cmd)
  //   cmdMgr.increaseUndo()
  //   // console.log('createPrimitive', result)
  //   // return wsApi.updateDocumentAndreadVisualData(result)
  // },
  createLinearBlock: async (
    startPoint: number[],
    endPoint: number[],
    height: number,
    width: number,
  ) => {
    const result = await wsApi.createPrimitiveBIM('Wall', {
      segment: {
        point1: startPoint,
        point2: endPoint,
        height: height,
        thickness: width,
      },
    });
    return result;
  },
  createMsolid: (
    params: {
      profile: string[];
    },
    preview = false,
  ) => {
    return wsApi.execCmd({
      c: 'CreateMsolid',
      p: preview,
      parent: wsApi.getParentId(),
      a: params,
    });
  },
  createMface: (
    params: {
      profile: string[];
    },
    preview = false,
  ) => {
    return wsApi.execCmd({
      c: 'CreateMface',
      p: preview,
      parent: wsApi.getParentId(),
      a: params,
    });
  },
  // 获取洞口定位信息
  getHoleInfo: async (holeFaceId: string) => {
    return await wsApi.execCmd({ e: 'BIM', c: 'GetHoleInfo', o: holeFaceId });
  },
  // ====== BIM命令 ======
  // ====== 模型评论标签 ======

  editMark: async (dxid: string, marks: Mark[]) => {
    return await wsApi.execCmd({
      c: 'EditMark',
      o: dxid,
      mark: marks,
    });
  },
  // ====== 模型评论标签 ======

  // ====== 基本信息 ======
  getVersionInfo: async () => {
    return await wsApi.execCmd({ c: 'GetVersion' });
  },

  // ====== 测量 ======
  measure: (dxid1: string, dxid2: string | undefined, showText: boolean) => {
    return wsApi.execCmd({
      c: 'Measure',
      dxid1,
      dxid2,
      text: showText,
    });
  },

  addMeasure: (result: RawMeasureResult) => {
    return wsApi.execCmd({
      c: 'AddMeasure',
      label: result.label,
      a: {
        dxid1: result.dxid1,
        dxid2: result.dxid2,
        text: result.text,
        result: result.result,
        ui: {},
      },
    });
  },

  deleteParameterLink(id: string) {
    return wsApi.execCmd({
      c: 'DeleteParameterLink',
      o: id,
    });
  },

  async getFormulaValue(fx: string) {
    return (
      await wsApi.execCmd({
        c: 'GetFormulaValue',
        fx,
      })
    ).val;
  },

  importBracketFile: async (params?: any) => {
    return await wsApi.execCmd({ c: 'GetBracketLoadFile', ...params });
  },

  execAiCmd: async (params) => {
    return await wsApi.execCmd({ e: 'AI', ...params });
  },
};
